home *** CD-ROM | disk | FTP | other *** search
/ MacWorld: Complete Mac Interactive / Macworld Complete Mac Interactive CD)(1994).iso / The Best of BMUG / Entertainment / Strategy / Bolo / Bolo Utilities / BoloBrains / Terminator Brain / terminator.c < prev    next >
C/C++ Source or Header  |  1993-09-28  |  32KB  |  1,137 lines

  1. /*--------------------------------------------------------------------------------
  2.     Copyright ©1993  Steve Israelson
  3.     All rights reserved.
  4.     
  5.     Permisson granted for personal use only.
  6. --------------------------------------------------------------------------------*/
  7. #include <FixMath.h>
  8. #include <Menus.h>
  9. #include <Events.h>
  10. #include <Resources.h>
  11. #include <stdarg.h>
  12. #include "debug.h"
  13. #include "Brain.h"
  14. #include "terminator.proto.h"
  15.  
  16. extern int vsprintf(char *sbuffer, char *fmt, va_list arg);
  17.  
  18. #define MyMenuID         1000
  19.  
  20. #define MIN_SPEED        10
  21.  
  22. #define NICE_LAND          (1 << ROAD | 1 << FOREST | 1 << GRASS)
  23. #define WATER            (1 << RIVER | 1 << SWAMP | 1 << CRATER)
  24. #define OBSTACLE        (1 << BUILDING | 1 << RUBBLE | 1 << HALFBUILDING)
  25. #define LAND            (NICE_LAND | WATER | OBSTACLE)
  26. #define UNITS            (1 << BOAT | 1 << REFBASE_T | 1 << PILLBOX_T)
  27.  
  28. #define clearkey(CONTROLVECTOR, COMMAND) CONTROLVECTOR &= ~(1<<COMMAND)
  29.  
  30. #define MAX_MSGS        16
  31. #define MIN_WAIT        (60 * 2)
  32. #define PILL_MSG        0
  33. #define BASE_MSG        1
  34. #define MOVE_MSG        2
  35.  
  36.  
  37. long             thinkStart;                /* start time for thinking */
  38. long            lastMsg,                 /* the last time a message was displayed */
  39.                 lastObstructed;            /* the last time we were obstructed */
  40. BrainInfo        *brainInfo;                /* the info packet */
  41. MenuHandle         MyMenu;                    /* the options menu */
  42. Boolean         aggressive;                /* menu option */
  43. Boolean         laymines;                /* menu option */
  44. Boolean         clearmines;                /* menu option */
  45. Boolean         placepills;                /* menu option */
  46. u_long            newKeys, newTaps,         /* new keys to press or tap */
  47.                 lastKeys, lastTaps;        /* last keys we pressed or tapped */
  48. short            repeatLastKeys;            /* should we repeat the last key? if so how many times */
  49. long            msgTimes[MAX_MSGS];        /* timers for the different msg types */
  50. ObjectInfo        *closestShot;            /* the closest shot to us */
  51. short            incoming_shells;        /* how many incomming shells */
  52. WORLD_X            lastSeenPillx;            /* last pillbox we have seen */
  53. WORLD_Y            lastSeenPilly;
  54. WORLD_X            basesx[16];                /* array of all the bases we have seen */
  55. WORLD_Y            basesy[16];
  56.  
  57. // For Mac fixed point trig routines, full circle is 2 * PI * 0x10000
  58. // We want full circle to be 0x100, so divide by (2 * PI * 0x10000 / 0x100)
  59. // which is 1608 in decimal
  60. /* assume us at 0,0 return angle to x,y (in fixed) */
  61. #define aim(X,Y)     ((FixATan2(-(Y),(X))/1608) & 0xFF)
  62.  
  63. // sin and cos routines are adjusted to take angles in the range 0-255
  64. // and return return values in the range +/-128
  65. #define sin(X)     ((short)(FracSin((u_char)(X)*1608L) >> 23))
  66. #define cos(X)     ((short)(FracCos((u_char)(X)*1608L) >> 23))
  67.  
  68. #define rangeFromMe(OB) findrange((OB)->x, (OB)->y, brainInfo->tankx, brainInfo->tanky)
  69.  
  70.  
  71. /*--------------------------------------------------------------------------------
  72.     The main brain killing machaine
  73. --------------------------------------------------------------------------------*/
  74. pascal short main(BrainInfo *theInfo)
  75.     {
  76.     if (theInfo->InfoVersion != CURRENT_BRAININFO_VERSION) 
  77.         return -1;
  78.  
  79.     brainInfo = theInfo;
  80.     thinkStart = TickCount();
  81.  
  82.     switch (brainInfo->operation)
  83.         {
  84.         case BRAIN_OPEN:    
  85.             if (openBrain()) 
  86.                 return 0;
  87.             closeBrain(); 
  88.             return -1;
  89.             break;
  90.         case BRAIN_CLOSE:    
  91.             closeBrain(); 
  92.             return 0;
  93.             break;
  94.         case BRAIN_THINK:    
  95.             think(); 
  96.             return 0;
  97.             break;
  98.         case MyMenuID:  
  99.             return(doMenu(brainInfo->menu_item));
  100.             break;
  101.         default:  
  102.             return 0;
  103.             break;
  104.         }
  105.     }
  106.  
  107. /*--------------------------------------------------------------------------------
  108.     Init all our globals.  Set up menus.
  109. --------------------------------------------------------------------------------*/
  110. Boolean openBrain(void)
  111.     {
  112.     short        x;
  113.  
  114.     aggressive = laymines = clearmines = placepills = true;
  115.     lastKeys = lastTaps = lastObstructed = 0;
  116.     repeatLastKeys = 0;
  117.     lastSeenPilly = lastSeenPillx = 0;
  118.     for (x = 0; x < 16; ++x)
  119.         basesx[x] = basesy[x] = 0;
  120.     lastMsg = TickCount();
  121.  
  122.     InsertMenu(MyMenu = GetMenu(MyMenuID), 0);
  123.     DrawMenuBar();
  124.     CheckItem(MyMenu, 1, aggressive);
  125.     CheckItem(MyMenu, 2, laymines);
  126.     CheckItem(MyMenu, 3, clearmines);
  127.     CheckItem(MyMenu, 4, placepills);
  128.     
  129.     for (x = 0; x < MAX_MSGS; ++x)
  130.         msgTimes[x] = 0;
  131.  
  132.     return true;
  133.     }
  134.  
  135. /*--------------------------------------------------------------------------------
  136.     Trash our menus.
  137. --------------------------------------------------------------------------------*/
  138. void closeBrain(void)
  139.     {
  140.     DeleteMenu(MyMenuID);
  141.     ReleaseResource((Handle)MyMenu);
  142.     DrawMenuBar();
  143.     }
  144.  
  145. /*--------------------------------------------------------------------------------
  146.     Do a menu, maybe someday actually do something here.
  147. --------------------------------------------------------------------------------*/
  148. short doMenu(short item)
  149.     {
  150.     switch (item)
  151.         {
  152.         case 1: 
  153.             CheckItem(MyMenu, 1, aggressive ^= 1);
  154.             break;
  155.         case 2: 
  156.             CheckItem(MyMenu, 2, laymines   ^= 1);
  157.             break;
  158.         case 3: 
  159.             CheckItem(MyMenu, 3, clearmines ^= 1);
  160.             break;
  161.         case 4: 
  162.             CheckItem(MyMenu, 4, placepills ^= 1);
  163.             break;
  164.         default: 
  165.             return -1;
  166.         }
  167.     return 0;
  168.     }
  169.  
  170. /*--------------------------------------------------------------------------------
  171.     I think, therfore I kill.  Do man actions, then move actions, then others.
  172. --------------------------------------------------------------------------------*/
  173. void think(void)
  174.     {
  175.     newKeys = 0;
  176.     newTaps = 0;
  177.  
  178.     countIncommingShots();
  179.  
  180.     if (!doMan())        /* place pills, lay mines */
  181.         doMove();
  182.     doOther();
  183.     
  184.     *(brainInfo->holdkeys) = newKeys;
  185.     *(brainInfo->tapkeys) = newTaps;
  186.     lastKeys = newKeys;
  187.     lastTaps = newTaps;
  188.     }
  189.  
  190. /*--------------------------------------------------------------------------------
  191.     Move our tank, sitting still is useless unless we are refuling.
  192.     You should rank these according the priority you think these are.
  193. --------------------------------------------------------------------------------*/
  194. Boolean doMove(void)
  195.     {
  196.     if (avoidDeepWater())
  197.         return true;
  198.     if (avoidMines())
  199.         return true;
  200.     if (checkObstructions())
  201.         return true;
  202.     if (avoidShots())
  203.         return true;
  204.     if (avoidPill())
  205.         return true;
  206.     if (avoidEnemy())
  207.         return true;
  208.     if (getMan())
  209.         return true;
  210.     if (avoidWater())
  211.         return true;
  212.     if (approachEnemyPill())
  213.         return true;
  214.     if (approachBase())
  215.         return true;
  216.     if (approachEnemyBase())
  217.         return true;
  218.  
  219.     selectRoute();
  220.  
  221.     /* if nothing to do then speed up! Places to go etc.. */
  222.     speedUp();
  223.     return false;
  224.     }
  225.  
  226. /*--------------------------------------------------------------------------------
  227.     Refuel if we are low.  Capture nearby neutral bases.
  228. --------------------------------------------------------------------------------*/
  229. Boolean approachBase(void)
  230.     {
  231.     long        range;
  232.     ObjectInfo    *ob;
  233.     short        x, closestBase = -1;
  234.     long        minDistance = 0x7fffffff;
  235.     Boolean        found;
  236.  
  237.     if (!brainInfo->base)        /* no base nearby so look for some farther away */
  238.         {
  239.         for (ob = &brainInfo->objects[0]; ob < &brainInfo->objects[brainInfo->num_objects]; ob++)
  240.             {
  241.             if (ob->info & OBJECT_HOSTILE)
  242.                 continue;
  243.             if (ob->object == OBJECT_REFBASE && ob->info & OBJECT_NEUTRAL)
  244.                 {
  245.                 range = rangeFromMe(ob);
  246.                 if ((range >> 8) < 14)
  247.                     {
  248.                     if (nearestEnemyPill(ob->x, ob->y))        /* should check distance here ##### */
  249.                         continue;
  250.                     /*sendDebugMsg(BASE_MSG, "B%d,%d", (int)(ob->x >> 8), (int)(ob->y >> 8));*/
  251.                     approachSpace(ob->x, ob->y);
  252.                     return speedUp();
  253.                     }
  254.                 }
  255.             if (!brainInfo->carriedpills && brainInfo->armour > 7 
  256.                     && brainInfo->shells > 20  && brainInfo->mines > 10)
  257.                 continue;
  258.             }
  259.         
  260.         /* no acceptable base nearby, so if we need it, lets find one we have been to before */
  261.         if (brainInfo->armour < 4)
  262.             {
  263.             for (x = 0; x < 16; ++x)
  264.                 {
  265.                 if (basesx[x] || basesy[x])
  266.                     {
  267.                     range = findrange(basesx[x], basesy[x], brainInfo->tankx, brainInfo->tanky);
  268.                     if (range < minDistance)
  269.                         {
  270.                         minDistance = range;
  271.                         closestBase = x;
  272.                         }
  273.                     }
  274.                 }
  275.             if (closestBase != -1)
  276.                 {
  277. /* sendDebugMsg(BASE_MSG, "Seek RB %d,%d",basesx[closestBase] >> 8,basesy[closestBase] >> 8); */
  278.                 approachSpace(basesx[closestBase], basesy[closestBase]);
  279.                 speedUp();
  280.                 return true;
  281.                 }
  282.             }
  283.         return false;
  284.         }
  285.  
  286.     /* nearby hostile base, ignore -- later maybee we should kill it */
  287.     if (brainInfo->base->info & OBJECT_HOSTILE)
  288.         return false;
  289.  
  290.     /* are we on a base, if so sit still */
  291.     if (terrainSpot() == REFBASE_T)
  292.         {
  293.         found = false;
  294.         for (x = 0; x < 16; ++x)
  295.             {
  296.             if (basesx[x] || basesy[x])
  297.                 continue;
  298.             if ((basesx[x] >> 8) == (brainInfo->tankx >> 8) 
  299.                         && (basesy[x] >> 8) == (brainInfo->tanky >> 8))
  300.                 {
  301.                 found = true;
  302.                 break;
  303.                 }
  304.             }
  305.         if (!found)        /* add to our database */
  306.             for (x = 0; x < 16; ++x)
  307.                 {
  308.                 if (basesx[x] || basesy[x])
  309.                     continue;
  310.                 basesx[x] = brainInfo->tankx;
  311.                 basesy[x] = brainInfo->tanky;
  312.     /* sendDebugMsg(BASE_MSG, "RBS %d,%d", brainInfo->tankx >> 8, brainInfo->tanky >> 8); */
  313.                 break;
  314.                 }
  315.  
  316.         slowDown();    
  317.         /* stay on the base until fueled */
  318.  
  319.         if (brainInfo->base_armour > MIN_BASE_ARMOUR && brainInfo->armour != 8)
  320.             return true;
  321.         if (brainInfo->base_shells && brainInfo->shells != 40)
  322.             return true;
  323.         if (brainInfo->base_mines && brainInfo->mines != 40)
  324.             return true;
  325.  
  326.         /* lets get going, places to go things to kill */
  327.         speedUp();
  328.         return false;
  329.         }
  330.  
  331.     /* approach the nearby base, unless there is an enemy pill nearby */
  332.     if (!(brainInfo->base->info & OBJECT_NEUTRAL)
  333.             && !(brainInfo->carriedpills && brainInfo->man_status == 0)
  334.             && brainInfo->armour > 7 
  335.             && brainInfo->shells > 20 && brainInfo->mines > 10)
  336.         return false;
  337.  
  338.     if (brainInfo->base_armour <= MIN_BASE_ARMOUR || brainInfo->base_shells == 0
  339.                 || brainInfo->base_mines == 0)
  340.         return false;
  341.  
  342.     if (nearestEnemyPill(brainInfo->base->x, brainInfo->base->y))    /* should check distance here ##### */
  343.         return false;
  344.     
  345.     /*sendDebugMsg(BASE_MSG, "CB%d,%d", (int)(brainInfo->base->x >> 8), (int)(brainInfo->base->y >> 8));*/
  346.     approachSpace(brainInfo->base->x, brainInfo->base->y);
  347.     range = rangeFromMe(brainInfo->base);
  348.     if ((range >> 8) < 2 && brainInfo->speed > MIN_SPEED)
  349.         slowDown();
  350.     else
  351.         speedUp();
  352.     return true;
  353.     }
  354.  
  355. /*--------------------------------------------------------------------------------
  356.     Add code here to destroy!
  357. --------------------------------------------------------------------------------*/
  358. Boolean approachEnemyBase(void)
  359.     {
  360.     }
  361.  
  362. /*--------------------------------------------------------------------------------
  363.     Are we stuck?  then get unstuck and get going, busy busy busy.
  364. --------------------------------------------------------------------------------*/
  365. Boolean checkObstructions(void)
  366.     {
  367.     TERRAIN            nearSpace;
  368.     short            x, y;
  369.     Boolean            tryNewApproach = false;    /* try something else cause were still stuck */
  370.  
  371.     if (lastObstructed || brainInfo->tankobstructed)
  372.         {
  373.         sendDebugMsg(MOVE_MSG, "stk");
  374.         speedUp();
  375.         x = brainInfo->tankx >> 8;
  376.         y = brainInfo->tanky >> 8;
  377.  
  378.         if (!lastObstructed)
  379.             lastObstructed = TickCount() + 60;
  380.         else if (lastObstructed < TickCount())
  381.             lastObstructed = 0;
  382.         if (lastObstructed && lastObstructed < TickCount() + 20)
  383.             tryNewApproach = true;
  384.         nearSpace = raw_getmapcell(x - 1, y) & TERRAIN_MASK;
  385.         if (nearSpace != BUILDING && nearSpace != HALFBUILDING && nearSpace != DEEPSEA)
  386.             {
  387.             if (!tryNewApproach)
  388.                 {
  389.                 approachSpace((x - 1) << 8, y << 8);
  390.                 return speedUp();
  391.                 }
  392.             tryNewApproach = false;
  393.             }
  394.         nearSpace = raw_getmapcell(x + 1, y) & TERRAIN_MASK;
  395.         if (nearSpace != BUILDING && nearSpace != HALFBUILDING && nearSpace != DEEPSEA)
  396.             {
  397.             if (!tryNewApproach)
  398.                 {
  399.                 approachSpace((x + 1) << 8, (y) << 8);
  400.                 return speedUp();
  401.                 }
  402.             tryNewApproach = false;
  403.             }
  404.         nearSpace = raw_getmapcell(x, y - 1) & TERRAIN_MASK;
  405.         if (nearSpace != BUILDING && nearSpace != HALFBUILDING && nearSpace != DEEPSEA)
  406.             {
  407.             if (!tryNewApproach)
  408.                 {
  409.                 approachSpace((x) << 8, (y - 1) << 8);
  410.                 return speedUp();
  411.                 }
  412.             tryNewApproach = false;
  413.             }
  414.         nearSpace = raw_getmapcell(x, y + 1) & TERRAIN_MASK;
  415.         if (nearSpace != BUILDING && nearSpace != HALFBUILDING && nearSpace != DEEPSEA)
  416.             {
  417.             if (!tryNewApproach)
  418.                 {
  419.                 approachSpace((x) << 8, (y + 1) << 8);
  420.                 return speedUp();
  421.                 }
  422.             tryNewApproach = false;
  423.             }
  424.  
  425.         sendDebugMsg(MOVE_MSG, "fire");
  426.         if (!approachObject(TERRAIN_MASK, BUILDING, 1, 128))
  427.             approachObject(TERRAIN_MASK, HALFBUILDING, 1, 128);
  428.         setkey(newTaps, KEY_shoot);
  429.         return true;
  430.         }
  431.     return false;
  432.     }
  433.  
  434. /*--------------------------------------------------------------------------------
  435.     Select the best route to travel.  Randomly turn for variety.
  436. --------------------------------------------------------------------------------*/
  437. Boolean selectRoute(void)
  438.     {
  439.     u_char        x, y;
  440.  
  441.     if (repeatLastKeys)
  442.         {
  443.         newKeys = lastKeys;
  444.         --repeatLastKeys;
  445.         return true;
  446.         }
  447.     if (rnd(0, 100) < 98)
  448.         {
  449.         /* if it is close, then why turn */
  450.         if (findObject(TERRAIN_MASK, ROAD, 1, 64, &x, &y))
  451.             return false;
  452.         if (findObject(TERRAIN_MASK, FOREST, 1, 64, &x, &y))
  453.             return false;
  454.         if (findObject(TERRAIN_MASK, GRASS, 1, 64, &x, &y))
  455.             return false;
  456.  
  457.         /* if it is not close, but near, then turn */
  458.         if (approachObject(TERRAIN_MASK, ROAD, 4, 30))
  459.             return true;
  460.         if (approachObject(TERRAIN_MASK, FOREST, 4, 30))
  461.             return true;
  462.         if (approachObject(TERRAIN_MASK, GRASS, 4, 30))
  463.             return true;
  464.         if (approachObject(TERRAIN_MASK, ROAD, 14, 30))
  465.             return true;
  466.         if (approachObject(TERRAIN_MASK, FOREST, 14, 30))
  467.             return true;
  468.         if (approachObject(TERRAIN_MASK, GRASS, 14, 30))
  469.             return true;
  470.         }
  471.             
  472.     if (rnd(0, 100) < 50)
  473.         setkey(newKeys, KEY_turnleft);
  474.     else
  475.         setkey(newKeys, KEY_turnright);
  476.     repeatLastKeys = 5;
  477.     }
  478.  
  479. /*--------------------------------------------------------------------------------
  480.     Approach an enemy pill and decimate it.
  481. --------------------------------------------------------------------------------*/
  482. Boolean approachEnemyPill(void)
  483.     {
  484.     ObjectInfo         *ob;
  485.     u_long            range;
  486.     short            direction;
  487.     short            da;
  488.  
  489.     if (brainInfo->shells < 8)
  490.         return false;
  491.     for (ob = &brainInfo->objects[0]; ob < &brainInfo->objects[brainInfo->num_objects]; ob++)
  492.         {
  493.         if (ob->object == OBJECT_PILLBOX && (ob->info & OBJECT_HOSTILE))
  494.             {
  495.             if (brainInfo->armour <= 4 && ob->direction > 1)    /* wimp out only if damaged */
  496.                 continue;
  497.  
  498.             range = rangeFromMe(ob);
  499.             approachSpace(ob->x, ob->y);
  500.             if ((range >> 8) >= 7)
  501.                 {
  502. /*sendDebugMsg(PILL_MSG, "P%d,%d", (int)(ob->x >> 8), (int)(ob->y >> 8));*/
  503.                 speedUp();
  504.                 }
  505.             else
  506.                 if (ob->direction < 2)
  507.                     {
  508. /*sendDebugMsg(PILL_MSG, "P%d,%d", (int)(ob->x >> 8), (int)(ob->y >> 8));*/
  509.                     speedUp();
  510.                     }
  511.                 else
  512.                     slowDown();
  513.  
  514.             if (ob->direction && range >> 8 <= 7)    /* if not dead then kill! */
  515.                 {
  516.                 direction = aim((unsigned long)ob->x - (unsigned long)brainInfo->tankx, 
  517.                                 (unsigned long)ob->y - (unsigned long)brainInfo->tanky);
  518.                 da = brainInfo->direction - direction;
  519.                 if (da < 4 && da > -4)
  520.                     setkey(newTaps, KEY_shoot);
  521.                 }
  522.             lastSeenPillx = ob->x;
  523.             lastSeenPilly = ob->y;
  524. /*sendDebugMsg(PILL_MSG, "PS%d,%d", (int)(lastSeenPillx >> 8), (int)(lastSeenPilly >> 8));*/
  525.             return true;
  526.             }
  527.         }
  528.     if (brainInfo->armour > 4 && (lastSeenPilly || lastSeenPillx))
  529.         {
  530. /*sendDebugMsg(PILL_MSG, "PS%d,%d", (int)(lastSeenPillx >> 8), (int)(lastSeenPilly >> 8));*/
  531.         approachSpace(lastSeenPillx, lastSeenPilly);
  532.         if (findrange(brainInfo->tankx, brainInfo->tanky, lastSeenPillx, lastSeenPilly) >> 8 < 15)
  533.             lastSeenPillx = lastSeenPilly = 0;
  534.         speedUp();
  535.         return true;
  536.         }
  537.     return false;
  538.     }
  539.  
  540. /*--------------------------------------------------------------------------------
  541.     Return the nearest enemy pill.
  542. --------------------------------------------------------------------------------*/
  543. ObjectInfo *nearestEnemyPill(WORLD_X x, WORLD_Y y)
  544.     {
  545.     ObjectInfo         *ob, *closestPill;
  546.     u_long            range, closest;
  547.     short            direction;
  548.     short            da;
  549.  
  550.     closestPill = nil;
  551.     closest = 8 << 8;        /* must be close enough to shoot */
  552.     for (ob = &brainInfo->objects[0]; ob < &brainInfo->objects[brainInfo->num_objects]; ob++)
  553.         {
  554.         if (ob->object == OBJECT_PILLBOX && (ob->info & OBJECT_HOSTILE))
  555.             {
  556.             range = findrange(ob->x, ob->y, x, y);
  557.             if (range < closest)
  558.                 {
  559.                 closest = range;
  560.                 closestPill = ob;
  561.                 }
  562.             }
  563.         }
  564.     return closestPill;
  565.     }
  566.  
  567. /*--------------------------------------------------------------------------------
  568.     Shoot at hostiles and walls and clear mines, farm build recover man etc.
  569. --------------------------------------------------------------------------------*/
  570. Boolean doOther(void)
  571.     {
  572.     doMan();
  573.     }
  574.  
  575. /*--------------------------------------------------------------------------------
  576.     If the man is far away then wait for him.
  577.     If he is very far away, then go get him.
  578. --------------------------------------------------------------------------------*/
  579. Boolean getMan(void)
  580.     {
  581.     short        dx, dy;
  582.     long        distance;
  583.  
  584.     if (brainInfo->man_status > 1)        /* outside tank and alive, for now */
  585.         {
  586.         dx = (brainInfo->tankx >> 8) - (brainInfo->man_x >> 8);
  587.         dy = (brainInfo->tanky >> 8) - (brainInfo->man_y >> 8);
  588.         distance = dx * dx + dy * dy;
  589.         if (brainInfo->manobstructed == 2 || distance > 100)    /* go get him */
  590.             {
  591.             approachSpace(brainInfo->man_x, brainInfo->man_y);
  592.             return speedUp();
  593.             }
  594.         if (distance > 25)
  595.             return slowDown();
  596.         }
  597.     return false;
  598.     }
  599.  
  600. /*--------------------------------------------------------------------------------
  601.     Do things with the man.  Keep him safe when shells in the air.
  602. --------------------------------------------------------------------------------*/
  603. Boolean doMan(void)
  604.     {
  605.     if (incoming_shells)
  606.         return false;
  607.     if (brainInfo->trees)
  608.         {
  609.         if (brainInfo->man_status || brainInfo->inboat)
  610.             return false;
  611.         if (buildPill())
  612.             return false;
  613.         if (buildRoad())
  614.             return false;
  615.         }
  616.     if (getTrees())
  617.         return false;
  618.     return false;
  619.     }
  620.  
  621. /*--------------------------------------------------------------------------------
  622.     If we need to then build a road to make thinks go quicker.
  623. --------------------------------------------------------------------------------*/
  624. Boolean buildRoad(void)
  625.     {
  626.     TERRAIN        mapSpot;
  627.  
  628.     mapSpot = terrainSpot();
  629.     if (mapSpot == RIVER || mapSpot == SWAMP || mapSpot == CRATER 
  630.                     || mapSpot == RUBBLE || mapSpot == SWAMP)
  631.         {
  632.         if (mapSpot == RIVER || brainInfo->speed < 20)
  633.             {
  634.             brainInfo->build->action = BUILDMODE_ROAD;
  635.             brainInfo->build->x = brainInfo->tankx >> 8;
  636.             brainInfo->build->y = brainInfo->tanky >> 8;
  637.             return true;
  638.             }
  639.         }
  640.     return false;
  641.     }
  642.  
  643. /*--------------------------------------------------------------------------------
  644.     Build a pill near our base.
  645. --------------------------------------------------------------------------------*/
  646. Boolean buildPill(void)
  647.     {
  648.     if (!brainInfo->carriedpills)
  649.         return false;
  650.     if (!(brainInfo->armour <= 2 && incoming_shells))        /* if we are about to die, then build the thing */
  651.         {
  652.         if (!brainInfo->base)        /* no base nearby */
  653.             return false;
  654.     
  655.         if (brainInfo->base->info & OBJECT_HOSTILE)
  656.             return false;
  657.     
  658.         if ((rangeFromMe(brainInfo->base) >> 8) > 4)
  659.             return false;
  660.         }
  661.     
  662.     brainInfo->build->action = BUILDMODE_PBOX;
  663.     brainInfo->build->x = brainInfo->tankx >> 8;
  664.     brainInfo->build->y = brainInfo->tanky >> 8;
  665.  
  666.     return true;
  667.     }
  668.  
  669. /*--------------------------------------------------------------------------------
  670.     If we are getting low on trees, then go get some.
  671. --------------------------------------------------------------------------------*/
  672. Boolean getTrees(void)
  673.     {
  674.     long        range;
  675.     u_char        x, y;
  676.  
  677.     if (brainInfo->trees > 20)
  678.         return false;
  679.     
  680.     if (terrainSpot() == FOREST)
  681.         {
  682.         brainInfo->build->action = BUILDMODE_FARM;
  683.         brainInfo->build->x = brainInfo->tankx >> 8;
  684.         brainInfo->build->y = brainInfo->tanky >> 8;
  685.         return true;
  686.         }
  687.     
  688.     if (findObject(TERRAIN_MASK, FOREST, 6, 128, &x, &y))
  689.         {
  690.         brainInfo->build->action = BUILDMODE_FARM;
  691.         brainInfo->build->x = x;
  692.         brainInfo->build->y = y;
  693.         return true;
  694.         }
  695.     return false;
  696.     }
  697.  
  698. /*--------------------------------------------------------------------------------
  699.     Tally the shots comming at us.
  700. --------------------------------------------------------------------------------*/
  701. void countIncommingShots(void)
  702.     {
  703.     ObjectInfo     *ob;
  704.     short        n;
  705.     long        dx, dy, minDist;
  706.     char        dev;
  707.  
  708.     // Count all shells coming towards us.
  709.     incoming_shells = 0;
  710.     minDist = 100000;
  711.     closestShot = nil;
  712.     for (n = 0; n < brainInfo->num_objects; ++n)
  713.         {
  714.         ob = &(brainInfo->objects[n]);
  715.         if (ob->object == OBJECT_SHOT)
  716.             {
  717.             /* dev = difference in the shots direction of travel and our
  718.                 direction from the shot */
  719.             dx = (unsigned long)brainInfo->tankx - (unsigned long)ob->x;
  720.             dy = (unsigned long)brainInfo->tanky - (unsigned long)ob->y;
  721.             dev = ob->direction - aim(dx, dy);
  722.             if (dev > -45 && dev < 45) 
  723.                 {
  724.                 ++incoming_shells;
  725.                 if (minDist > (dx * dx + dy * dy))
  726.                     {
  727.                     minDist = dx * dx + dy * dy;
  728.                     closestShot = ob;
  729.                     }
  730.                 }
  731.             }
  732.         }
  733.     }
  734.  
  735. /*--------------------------------------------------------------------------------
  736.     Avoid the shots comming at us.
  737. --------------------------------------------------------------------------------*/
  738. Boolean avoidShots(void)
  739.     {
  740.     if ((incoming_shells > 4 || incoming_shells >= brainInfo->armour) && closestShot)
  741.         {
  742.         obliquelyAvoidSpace(closestShot->x, closestShot->y);
  743.         speedUp();
  744.         return true;
  745.         }
  746.     return false;
  747.     }
  748.  
  749. /*--------------------------------------------------------------------------------
  750.     If we are suddenly in water, then get out, and avoid it.
  751. --------------------------------------------------------------------------------*/
  752. Boolean avoidWater(void)
  753.     {
  754.     if (brainInfo->inboat)
  755.         return false;
  756.     if (terrainSpot() == RIVER)
  757.         {
  758.         /* #### perhaps build bridge here #### */
  759.         if (approachObject(TERRAIN_MASK, ROAD, 4, 30)
  760.                 || approachObject(TERRAIN_MASK, FOREST, 4, 30)
  761.                 || approachObject(TERRAIN_MASK, GRASS, 4, 30))
  762.         return speedUp();
  763.         }
  764.         
  765.     if (avoidObject(TERRAIN_MASK, RIVER, 2))
  766.         return speedUp();
  767.     return false;    
  768.     }
  769.  
  770. /*--------------------------------------------------------------------------------
  771.     Avoid map square.
  772. --------------------------------------------------------------------------------*/
  773. void avoidSpace(WORLD_X x, WORLD_Y y)
  774.     {
  775.     short            direction;
  776.  
  777.     direction = aim((unsigned long)x - (unsigned long)brainInfo->tankx, 
  778.                         (unsigned long)y - (unsigned long)brainInfo->tanky);
  779.  
  780.     if (direction > brainInfo->direction && direction - brainInfo->direction < 128)
  781.         setkey(newKeys, KEY_turnleft);
  782.     else if (direction < 128 && brainInfo->direction > 128 + direction)
  783.         setkey(newKeys, KEY_turnleft);
  784.     else
  785.         setkey(newKeys, KEY_turnright);
  786.     }
  787.  
  788. /*--------------------------------------------------------------------------------
  789.     Avoid map square at an angle.
  790. --------------------------------------------------------------------------------*/
  791. void obliquelyAvoidSpace(WORLD_X x, WORLD_Y y)
  792.     {
  793.     short            direction, da;
  794.  
  795.     direction = aim((unsigned long)x - (unsigned long)brainInfo->tankx, 
  796.                     (unsigned long)y - (unsigned long)brainInfo->tanky);
  797.  
  798.     if (direction > brainInfo->direction)
  799.         da = direction - brainInfo->direction;
  800.     else
  801.         da = brainInfo->direction - direction;
  802.     if (direction > brainInfo->direction && direction - brainInfo->direction < 128)
  803.         {
  804.         if (da < 90)
  805.             setkey(newKeys, KEY_turnleft);
  806.         }
  807.     else if (direction < 128 && brainInfo->direction > 128 + direction)
  808.         {
  809.         if (da < 90)
  810.             setkey(newKeys, KEY_turnleft);
  811.         }
  812.     else
  813.         {
  814.         if (da < 90)
  815.             setkey(newKeys, KEY_turnright);
  816.         }
  817.     }
  818.  
  819. /*--------------------------------------------------------------------------------
  820.     Approach map square.
  821. --------------------------------------------------------------------------------*/
  822. void approachSpace(WORLD_X x, WORLD_Y y)
  823.     {
  824.     short            direction;
  825.     char            da, max, min;
  826.     u_long            *keysToSet;
  827.     long            range;
  828.  
  829.     direction = aim((unsigned long)x - (unsigned long)brainInfo->tankx, 
  830.                         (unsigned long)y - (unsigned long)brainInfo->tanky);
  831.  
  832.     da = brainInfo->direction - direction;
  833.     range = (findrange(x, y, brainInfo->tankx, brainInfo->tanky)) >> 8;
  834. /*    if (range > 8)
  835.         {max = 7; min = 2;}
  836.     else if (range > 4)
  837.         {max = 10; min = 4;}
  838.     else if (range > 2)
  839.         {max = 20; min = 7;}
  840.     else
  841.         {max = 90; min = 45;}*/
  842.         
  843.     /*if (range > 15)
  844.         range = 15;
  845.     max = (15 - range) * 3;
  846.     min = (15 - range);*/
  847.  
  848.     max = 15;
  849.     min = 2;
  850.     if (da < max && da > -max)
  851.         keysToSet = &newTaps;
  852.     else
  853.         keysToSet = &newKeys;
  854.     if (da < min && da > -min)
  855.         return;
  856.     if (direction > brainInfo->direction && direction - brainInfo->direction < 128)
  857.         setkey(*keysToSet, KEY_turnright);
  858.     else if (direction < 128 && brainInfo->direction > 128 + direction)
  859.         setkey(*keysToSet, KEY_turnright);
  860.     else
  861.         setkey(*keysToSet, KEY_turnleft);
  862.     }
  863.  
  864. /*--------------------------------------------------------------------------------
  865.     If we are damaged, then avoid the pillboxes.
  866. --------------------------------------------------------------------------------*/
  867. Boolean avoidPill(void)
  868.     {
  869.     ObjectInfo         *ob;
  870.     u_long            range;
  871.  
  872.     if (brainInfo->armour >= 4)        /* do not avoid if we have armour */
  873.         return false;
  874.  
  875.     for (ob = &brainInfo->objects[0]; ob < &brainInfo->objects[brainInfo->num_objects]; ob++)
  876.         {
  877.         if (ob->object == OBJECT_PILLBOX && (ob->info & OBJECT_HOSTILE))
  878.             {
  879.             if (ob->direction <= 2)
  880.                 return false;
  881.             range = rangeFromMe(ob);
  882.             if ((range >> 8) > 8)
  883.                 continue;
  884.  
  885.             avoidSpace(ob->x, ob->y);
  886.  
  887.             return speedUp();
  888.             }
  889.         }
  890.     return false;
  891.     }
  892.  
  893. /*--------------------------------------------------------------------------------
  894.     Avoid enemies
  895. --------------------------------------------------------------------------------*/
  896. Boolean avoidEnemy(void)
  897.     {
  898.     }
  899.  
  900.  
  901. /*--------------------------------------------------------------------------------
  902.     Avoid nearby mines if we are moving, by turning and slowing.
  903. --------------------------------------------------------------------------------*/
  904. Boolean avoidMines(void)
  905.     {
  906.     u_char        x, y;
  907.     Boolean        mine;
  908.  
  909.     if (!brainInfo->speed)        /* we are stopped so no need to avoid */
  910.         return false;
  911.     
  912.     mine = findObject(TERRAIN_MINE, TERRAIN_MINE, 2, 10, &x, &y);
  913.     if (!mine)
  914.         if (!findObject(TERRAIN_MINE, TERRAIN_MINE, 1, 50, &x, &y))
  915.             return false;
  916.     avoidSpace(x << 8, y << 8);
  917.     if (brainInfo->speed > MIN_SPEED)
  918.         return slowDown();
  919.     else
  920.         return speedUp();
  921.     }
  922.  
  923. /*--------------------------------------------------------------------------------
  924.     Avoid going into deep water, and get out of it when dead.
  925. --------------------------------------------------------------------------------*/
  926. Boolean avoidDeepWater(void)
  927.     {
  928.     if (terrainSpot() == DEEPSEA)
  929.         {
  930.         /*approachObject(DEEPSEA, 0, 14, 128);*/    /* anything but deepsea */
  931.         if (!approachObject(TERRAIN_MASK, ROAD, 14, 128))
  932.         if (!approachObject(TERRAIN_MASK, GRASS, 14, 128))
  933.         if (!approachObject(TERRAIN_MASK, FOREST, 14, 128))
  934.         if (!approachObject(TERRAIN_MASK, SWAMP, 14, 128))
  935.         if (!approachObject(TERRAIN_MASK, RUBBLE, 14, 128))
  936.         if (!approachObject(TERRAIN_MASK, HALFBUILDING, 14, 128))
  937.         if (!approachObject(TERRAIN_MASK, BUILDING, 14, 128))
  938.             approachObject(TERRAIN_MASK, CRATER, 14, 128);
  939.  
  940.         return speedUp();
  941.         }
  942.         
  943.     if (avoidObject(TERRAIN_MASK, DEEPSEA, 4))
  944.         return slowDown();
  945.  
  946.     return false;    
  947.     }
  948.  
  949.  
  950. /*--------------------------------------------------------------------------------
  951.     Avoid nearby objects if we are moving, by turning away.
  952. --------------------------------------------------------------------------------*/
  953. Boolean avoidObject(u_char mask, TERRAIN thing, short distance)
  954.     {
  955.     u_char        x, y;
  956.     
  957.     if (!brainInfo->speed)
  958.         return false;
  959.     if (findObject(mask, thing, distance, 45, &x, &y))
  960.         {
  961.         avoidSpace(x << 8, y << 8);
  962.         return true;
  963.         }
  964.     return false;    /* no evasion needed */
  965.     }
  966.  
  967. /*--------------------------------------------------------------------------------
  968.     Turn towards nearby objects.
  969. --------------------------------------------------------------------------------*/
  970. Boolean approachObject(u_char mask, TERRAIN thing, short distance, short da)
  971.     {
  972.     u_char        x, y;
  973.     
  974.     if (findObject(mask, thing, distance, da, &x, &y))
  975.         {
  976.         approachSpace(x << 8, y << 8);
  977.         return true;
  978.         }
  979.     return false;
  980.     }
  981.  
  982. /*--------------------------------------------------------------------------------
  983.     Find the thing in the map we can see.
  984. --------------------------------------------------------------------------------*/
  985. Boolean findObject(u_char mask, TERRAIN thing, short distance, short da, u_char *x, u_char *y)
  986.     {
  987.     short        r;
  988.     BYTE        angle;
  989.     WORLD_X     wx;
  990.     WORLD_Y     wy;
  991.  
  992.     for (r = 1; r <= distance; ++r)
  993.         {
  994.         for (angle = 0; angle <= da; angle += 5)
  995.             {
  996.             wx = brainInfo->tankx + sin(brainInfo->direction + angle) * r;
  997.             wy = brainInfo->tanky - cos(brainInfo->direction + angle) * r;
  998.             if (wx >> 8 == brainInfo->tankx >> 8 && wy >> 8 == brainInfo->tanky >> 8)
  999.                 continue;
  1000.     
  1001.             if ((raw_getmapcell(wx >> 8, wy >> 8) & mask) == thing)
  1002.                 {
  1003.                 *x = wx >> 8;
  1004.                 *y = wy >> 8;
  1005.                 return true;
  1006.                 }
  1007.             wx = brainInfo->tankx + sin(brainInfo->direction - angle) * r;
  1008.             wy = brainInfo->tanky - cos(brainInfo->direction - angle) * r;
  1009.             if (wx >> 8 == brainInfo->tankx >> 8 && wy >> 8 == brainInfo->tanky >> 8)
  1010.                 continue;
  1011.     
  1012.             if ((raw_getmapcell(wx >> 8, wy >> 8) & mask) == thing)
  1013.                 {
  1014.                 *x = wx >> 8;
  1015.                 *y = wy >> 8;
  1016.                 return true;
  1017.                 }
  1018.             }
  1019.         }
  1020.     return false;
  1021.     }
  1022.  
  1023. /*--------------------------------------------------------------------------------
  1024.     Return the terrain info from the map location near us.
  1025. --------------------------------------------------------------------------------*/
  1026. TERRAIN mapNearUs(u_char direction, char distance)
  1027.     {
  1028.     WORLD_X     wx, wy;
  1029.  
  1030.     wx = brainInfo->tankx + sin(direction) * distance;
  1031.     wy = brainInfo->tanky - cos(direction) * distance;
  1032.  
  1033.     return raw_getmapcell(wx >> 8, wy >> 8);
  1034.     }
  1035.  
  1036. /*--------------------------------------------------------------------------------
  1037.     Return the terrain info from the map.
  1038. --------------------------------------------------------------------------------*/
  1039. TERRAIN raw_getmapcell(MAP_X x, MAP_Y y)
  1040.     {
  1041.     if (x < brainInfo->view_left || y < brainInfo->view_top) 
  1042.         return(DEEPSEA);
  1043.     y -= brainInfo->view_top;
  1044.     x -= brainInfo->view_left;
  1045.     if (x >= brainInfo->view_width || y >= brainInfo->view_height) 
  1046.         return(DEEPSEA);
  1047.     return (brainInfo->viewdata[y * brainInfo->view_width + x]);
  1048.     }
  1049.  
  1050. /*--------------------------------------------------------------------------------
  1051.     Send a debug msg to ourselves.
  1052. --------------------------------------------------------------------------------*/
  1053. void sendDebugMsg(short msgIndex, char *theMessage, ...)
  1054.     {
  1055.     short        x;
  1056.     char        buffer[256];
  1057.     va_list     ptr;
  1058.  
  1059.     *(brainInfo->messagedest) = 0xFFFFFFFF;
  1060.     if (!brainInfo->sendmessage[0])
  1061.         {
  1062.         if (TickCount() < lastMsg)
  1063.             return;
  1064.         if (msgIndex >= MAX_MSGS)
  1065.             return;
  1066.         if (TickCount() - msgTimes[msgIndex] <= MIN_WAIT)
  1067.             return;
  1068.         msgTimes[msgIndex] = TickCount();
  1069.         lastMsg = TickCount() + 60;
  1070.     
  1071.         va_start(ptr, theMessage);
  1072.         buffer[0] = vsprintf((char *)buffer+1, theMessage, ptr);
  1073.  
  1074.         for (x = 0; x <= buffer[0]; ++x)
  1075.             brainInfo->sendmessage[x] = buffer[x];
  1076.         }
  1077.     }
  1078.  
  1079. /*--------------------------------------------------------------------------------
  1080.     Find the distance between two objects
  1081. --------------------------------------------------------------------------------*/
  1082. u_long findrange(long x1, long y1, long x2, long y2)
  1083.     {
  1084.     long        dx, dy;
  1085.     
  1086.     dx = x1 - x2;
  1087.     dy = y1 - y2;
  1088.     return (FracSqrt(dx * dx + dy * dy) >> 15);
  1089.     }
  1090.  
  1091. /*--------------------------------------------------------------------------------
  1092.      return a number between min - 1 and max
  1093. --------------------------------------------------------------------------------*/
  1094. unsigned short rnd(short min, short max)
  1095.     {
  1096.     unsigned short        ranNum;
  1097.     long                range, t;
  1098.     
  1099.     ranNum = Random();
  1100.     range = max - min;
  1101.     t = (ranNum * range) / 65536;
  1102.     return (t + min);
  1103.     }
  1104.  
  1105. /*--------------------------------------------------------------------------------
  1106.     Slow down.
  1107. --------------------------------------------------------------------------------*/
  1108. Boolean slowDown(void)
  1109.     {
  1110.     setkey(newKeys, KEY_slower);
  1111.     clearkey(newKeys, KEY_faster);
  1112.     return true;
  1113.     }
  1114.  
  1115. /*--------------------------------------------------------------------------------
  1116.     Speed up.
  1117. --------------------------------------------------------------------------------*/
  1118. Boolean speedUp(void)
  1119.     {
  1120.     setkey(newKeys, KEY_faster);
  1121.     clearkey(newKeys, KEY_slower);
  1122.     return true;
  1123.     }
  1124.  
  1125. /*--------------------------------------------------------------------------------
  1126.     The terrain at the spot.
  1127. --------------------------------------------------------------------------------*/
  1128. TERRAIN terrainSpot(void)
  1129.     {
  1130.     return raw_getmapcell(brainInfo->tankx >> 8, brainInfo->tanky >> 8) & TERRAIN_MASK;
  1131.     }
  1132.  
  1133.  
  1134.  
  1135.  
  1136.  
  1137.